/*
 * Copyright (c) 2012-2014 Wind River Systems, Inc.
 *
 * SPDX-License-Identifier: Apache-2.0
 */

#include <zephyr/kernel.h>
#include <nrfx_uarte.h>
#include <hal/nrf_gpio.h>
#include <zephyr/logging/log.h>
#include <stdio.h>
#include "display.h"

LOG_MODULE_REGISTER(main, LOG_LEVEL_DBG);

#define UARTE_INST_IDX 0

#define RX_BUFFER_SIZE 256
#define RX_END_SYMBOL '\n'
#define INSTANCE_ID_BASE "LED_MATRIX"

#define UART_TX_PIN NRF_GPIO_PIN_MAP(0, 6)
#define UART_RX_PIN NRF_GPIO_PIN_MAP(0, 8)

static nrfx_uarte_t uarte_instance = NRFX_UARTE_INSTANCE(UARTE_INST_IDX);

uint8_t rx_buffer[RX_BUFFER_SIZE];
uint16_t rx_buffer_index = 0;
uint8_t rx_data;

uint8_t get_uart_rx_data(void)
{
	nrfx_uarte_rx(&uarte_instance, &rx_data, sizeof(rx_data));
	return rx_data;
}

void send_uart_data(uint8_t *data, size_t len)
{
	nrfx_uarte_tx(&uarte_instance, data, len);
}

void echo_uart_data(void)
{
	uint8_t echo_str[4] = "OK\r\n";
	send_uart_data(echo_str, sizeof(echo_str));
}

void uart_data_process(uint8_t *data, size_t len)
{

	if(data[0] == 0 && data[1] == 0x10 && len >=12) {	// match the command
		LOG_INF("Ready a new data block");
		uint16_t id = (data[3] << 8) | data[4];
		uint16_t frame = (data[5] << 8) | data[6];
		uint8_t col = data[7];
		uint8_t row = data[8];
		uint16_t inv = (data[9] << 8) | data[10];
		uint16_t crc = (data[11] << 8) | data[12];

		LOG_INF("ID: %d, Frame: %d, Col: %d, Row: %d, CRC: %d", id, frame, col, row, crc);
		echo_uart_data();
		set_block_info(id, frame, col, row, inv);
	}
	if(data[0] == 0 && data[1] == 0x11 && len >= (8 + get_row((data[3] << 8) | data[4]) * 3)) {
		LOG_INF("Rceived a block of data");
		uint16_t id = (data[3] << 8) | data[4];
		uint16_t frame = (data[5] << 8) | data[6];
		uint8_t col = data[7];
		uint8_t row_max = get_row(id);

		for(uint8_t i = 0; i < row_max; i++) {
			set_block_data(id, frame, col, i, data[8 + i * 3], data[9 + i * 3], data[10 + i * 3]);
		}
		echo_uart_data();
	}

	if(data[0] == 0 && data[1] == 0x12 && len >= 11) {
		LOG_INF("finish a block of data received");
		uint16_t id = (data[3] << 8) | data[4];
		uint16_t block_crc = (data[5] << 8) | data[6];
		enum cycle_mode_e cycle_mode;
		enum play_mode_e play_mode;

		if (data[7] == 0) {
			cycle_mode = CYCLE_ONCE;
		} else {
			cycle_mode = CYCLE_LOOP;
		}

		if (data[8] == 0) {
			play_mode = PLAY_NOW;
		} else {
			play_mode = PLAY_QUEUE;
		}

		uint16_t crc = (data[9] << 8) | data[10];

		set_play_mode(id, play_mode);
		set_cycle_mode(id, cycle_mode);

		echo_uart_data();
	}
}

static void uart_handler(nrfx_uarte_event_t const * p_event, void * p_context)
{
	uint8_t rx;

	switch (p_event->type) {
		case NRFX_UARTE_EVT_TX_DONE:
			break;
		case NRFX_UARTE_EVT_RX_DONE:

			rx = get_uart_rx_data();
			rx_buffer[rx_buffer_index] = rx;

			if(rx_buffer_index > RX_BUFFER_SIZE) rx_buffer_index = 0;
			if(rx_buffer_index >= 2) rx_buffer_index++;
			if(rx == 0x55 && rx_buffer_index == 0) rx_buffer_index = 1;
			if(rx == 0xAA && rx_buffer_index == 1) rx_buffer_index = 2;

			if(rx == RX_END_SYMBOL && rx_buffer_index > 2 && rx_buffer[rx_buffer_index - 2] == '\r') {
				rx_buffer_index = 0;
				LOG_HEXDUMP_DBG(rx_buffer, sizeof(rx_buffer), "Received data");
				uart_data_process(rx_buffer + 2, sizeof(rx_buffer) - 2);
			}

			break;
		case NRFX_UARTE_EVT_ERROR:
			break;
		default:
			break;
	}
}

int main(void)
{
	nrfx_err_t err;

	nrfx_uarte_config_t uarte_config = NRFX_UARTE_DEFAULT_CONFIG(UART_TX_PIN, UART_RX_PIN);
	uarte_config.p_context = &uarte_instance;
	err = nrfx_uarte_init(&uarte_instance, &uarte_config, uart_handler);
	IRQ_DIRECT_CONNECT(NRFX_IRQ_NUMBER_GET(NRF_UARTE_INST_GET(UARTE_INST_IDX)), IRQ_PRIO_LOWEST,
                       NRFX_UARTE_INST_HANDLER_GET(UARTE_INST_IDX), 0);
	nrfx_uarte_rx(&uarte_instance, &rx_data, sizeof(rx_data));

	display_block_init();

	while (1) {
		k_sleep(K_MSEC(1000));
	}

	return 0;
}
